package by.dezhits.liltweets.task;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.entity.BufferedHttpEntity;
import org.apache.http.impl.client.DefaultHttpClient;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Build;
import by.dezhits.liltweets.ContextHolder;
import by.dezhits.liltweets.images.ImageLoader.Callback;
import by.dezhits.liltweets.images.ImageLoader.ConvertOnLoadMode;
import by.dezhits.liltweets.images.ImageProccessor;
import by.dezhits.liltweets.utils.MD5;

public class ImageAsyncTask extends AsyncTask<String, Void, Object> {

	private static final int CORE_POOL_SIZE = 5;
	private static final int MAXIMUM_POOL_SIZE = 128;
	private static final int KEEP_LIVE = 1;
	private static final ThreadFactory sThreadFactory = new ThreadFactory() {
		private final AtomicInteger mCount = new AtomicInteger(1);

		public Thread newThread(Runnable r) {
			return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
		}
	};
	private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(
			10);
	public static final Executor IMAGE_LOAD_EXECUTOR = new ThreadPoolExecutor(
			CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_LIVE, TimeUnit.SECONDS,
			sPoolWorkQueue, sThreadFactory);

	private Callback callback;

	private ConvertOnLoadMode mode;

	public ImageAsyncTask(Callback callback) {
		this.callback = callback;
		this.mode = callback.getLoadMode();
	}

	@Override
	protected Object doInBackground(String... params) {

		InputStream is = null;
		FileInputStream fis = null;
		FileOutputStream fos = null;
		ByteArrayOutputStream bos = null;
		try {
			String url = params[0];
			String md5_url = MD5.md5(url);
			Bitmap bitmap = null;
			Context context = ContextHolder.getInstance().getContext();
			File cacheDir = context.getCacheDir();
			File cacheFile = new File(cacheDir, md5_url);
			if (cacheFile.exists()) {
				fis = new FileInputStream(cacheFile);
				int l = fis.available();
				byte[] b = new byte[l];
				fis.read(b);
				bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
				return bitmap;
			} else {
				HttpClient client = new DefaultHttpClient();
				HttpGet get = new HttpGet(url);
				HttpResponse resp = client.execute(get);
				BufferedHttpEntity ent = new BufferedHttpEntity(
						resp.getEntity());
				if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
					return null;
				}
				is = ent.getContent();
				byte[] bitmap_byte = new byte[is.available()];
				is.read(bitmap_byte);
				bitmap = BitmapFactory.decodeByteArray(bitmap_byte, 0,
						bitmap_byte.length);
				Bitmap moddedBitmap = null;
				if (mode == ConvertOnLoadMode.ROUND) {
					moddedBitmap = ImageProccessor.getRoundedCornersImage(
							bitmap, 10);
				} else if (mode == ConvertOnLoadMode.NORMAL) {
					moddedBitmap = bitmap;
				}
				bos = new ByteArrayOutputStream();
				moddedBitmap.compress(CompressFormat.PNG, 0, bos);
				byte[] bytes = bos.toByteArray();
				fos = new FileOutputStream(cacheFile);
				fos.write(bytes);
				return moddedBitmap;
			}
		} catch (Exception e) {
			return e;
		} finally {
			try {
				fis.close();
				is.close();
				fos.close();
				bos.close();
			} catch (Exception e) {
				// Ignored already closed or never opened
			}
		}
	}

	@Override
	protected void onPostExecute(Object result) {
		super.onPostExecute(result);
		if (result instanceof Bitmap) {
			Bitmap bitmap = (Bitmap) result;
			callback.success(bitmap);
		} else {
			callback.onError((Exception) result);
		}
	}

	@TargetApi(11)
	public void start(String url) {
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
			/*
			 * try { Class c = this.getClass(); Method m =
			 * c.getMethod("executeOnExecutor", Executor.class, Object[].class);
			 * Field f = AsyncTask.class.getField("THREAD_POOL_EXECUTOR");
			 * m.invoke(this, f.get(this), new String[] { url }); } catch
			 * (Exception e) { }
			 */
			executeOnExecutor(IMAGE_LOAD_EXECUTOR, url);
		} else {
			execute(url);
		}
	}
}
